/****************************************************************************
 *   Copyright (C) 2008 by 7552                                             *
 *   fiubataller2-08c1@gruposyahoo.com.ar                                   *
 *                                                                          *
 *  Licensed under the Apache License, Version 2.0 (the "License");         *
 *  you may not use this file except in compliance with the License.        *
 *  You may obtain a copy of the License at                                 *
 *                                                                          *
 *      http://www.apache.org/licenses/LICENSE-2.0                          *
 *                                                                          *
 *  Unless required by applicable law or agreed to in writing, software     *
 *  distributed under the License is distributed on an "AS IS" BASIS,       *
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 *  See the License for the specific language governing permissions and     *
 *  limitations under the License.                                          *
 *                                                                          *
 ***************************************************************************/

#ifndef _TRANSACTIONMANAGER_
#define _TRANSACTIONMANAGER_

#include <list>
#include <string>
#include <map>
#include <cstdio>
#include <pthread.h>
#include "LogCache.h"
#include "IScheduler.h"

#define CHECKPOINT_INTERVAL 25

using namespace std;

namespace Taller2
{
namespace TransRec
{

const int NULL_TRANSACTION = -1;

class TransactionManager
{
public:

    /**
    	\brief Devuelve la unica instancia de esta clase. Si no existe, la crea
    	\return Instancia del TransactionManager.
     */
    static TransactionManager* Instance(IScheduler* pScheluder, const string& database = _DEFAULT_DB_);

    /**
    	\brief Libera los recursos utilizados por el TransactionManager asociado a \b database.
     */
    static void CloseTransactionManager(const string& database = _DEFAULT_DB_);

    /**
    	\brief Destructor de la clase.
    */
    ~TransactionManager();

    /**
    	\brief Comienza una nueva transacci�n.
    	Genera un id unico de transaccion y lo devuelve. No inserta nada en el log,
    	por lo tanto no controla de ninguna forma que la transaccion termine (commit o rollback)
    	\return Devuelve el ID de la transacci�n creada.
     */
    int BeginTransaction();

    /**
    	\brief Hace permanente los cambios realizados por la transcci�n.
     	Escribe en el log un registro de commit de la transaccion, flushea la cache de log (FLC) y retorna
     	@see http://en.wikipedia.org/wiki/ACID#Durability
    	\param transactionId  ID de la transacci�n a terminar.
    	\return TBC
     */
    int CommitTransaction(const int transactionId);

    /**
    	\brief Deshace los cambios realizados por la transacci�n.
    	Flushea la cache de log y luego escribe en el log no volatil un registro de abort de
    	la transaccion. Luego recorre el log hacia atras deshaciendo las operaciones de esa transaccion.
    	Pide operaciones a operatoria, pasa por buffer, no lockea objetos porque ya estan lockeados
    	previamente por quien haya ordenado las operaciones. Desbloquea todos los objetos al terminar.
    	\param transactionId  ID de la transacci�n a terminar.
    	\return TBC
     */
    int RollbackTransaction(const int transactionId);

    /**
    	\brief Actualiza la cache de log del TransactionManager de acuerdo a la operaci�n a realizar.
    	Este metodo se ejecuta antes de una escritura sobre el cache de la base de datos, y debe
    	terminar antes de que la escritura comience. Escribe sobre la cache de log la operacion a
    	realizar, incluyendo estado viejo y nuevo del objeto en cuestion.
    	\param objectID ID del objeto a modificar.
    	\param oldObject Serializaci�n del objeto antes de ser modificado. Si el objeto va a ser creado �ste parametro es NULL.
    	\param oldObjectSize Tama�o en bytes de \b oldObject.
    	\param newObject Serializaci�n del objeto luego de ser modificado. Si el objeto va a ser destruido �ste parametro es NULL.
    	\param newObjectSize Tama�o en bytes de \b newObject.
    	\param transactionID ID de la transacci�n.
    */
    int PreWrite(const long long objectId, const char* oldObject, const int oldObjectSize, const char* newObject, const int newObjectSize, const int transactionId);

    /**
    	\brief Actualiza la cache de log del TransactionManager de acuerdo a la operaci�n a realizar.
    	@see PreWrite(const long long, const char*, const int, const char*, const int, const int)
    	Esta operacion se invoca cuando se va a llamar una operacion que es en si misma una transaccion.
    	\param objectID ID del objeto a modificar.
    	\param oldObject Serializaci�n del objeto antes de ser modificado. Si el objeto va a ser creado �ste parametro es NULL.
    	\param oldObjectSize Tama�o en bytes de \b oldObject.
    	\param newObject Serializaci�n del objeto luego de ser modificado. Si el objeto va a ser destruido �ste parametro es NULL.
    	\param newObjectSize Tama�o en bytes de \b newObject.
    	\param transactionID ID de la transacci�n.
     */
    int PreWrite(const long long objectId, const char* oldObject, const int oldObjectSize, const char* newObject, const int newObjectSize);

    /**
    	\brief Actualiza la cahce de log antes de que Buffer flushee sus objetos a disco.
    	Este metodo se ejecuta antes de flushear cualquier pagina u objeto del buffer-cache de la base
    	de datos al disco, y debe terminar antes de que ese flush comience. Flushea la cache de log
    	(WAL) y retorna.
    	\param objectIDsToFlush lista con los ID de los objetos a guardar.
     */
    void PreFlushCache(const list<long long>& objectIdsToFlush);

private:

    /**
    	 Constructor privado: es un singleton
    */
    TransactionManager(const string &database);

    /**
    	Mapa con las instancias creadas para cada base de datos
     */
    //static TransactionManager* instance;
    typedef map<string, TransactionManager*> TTransactionManagerMap;
    static TTransactionManagerMap instances;

	int ContOpe; //contador de contador de operaciones

    /**
    	Se llama cada vez que se considera que corresponde escribir un checkpoint
    	@see http://en.wikipedia.org/wiki/Transaction_checkpoint#Recovery_Process
     */
    void WriteCheckpoint();

    /**
    	Representa el id de la proxima transaccion que sea pedida.
     */
    int nextTransactionId;
    pthread_mutex_t critical_section;

    Taller2::TransRec::LogCache logCache;
 	IScheduler* scheduler;
};
};
};

#endif
